﻿using System;
using System.Collections.Generic;
using System.IO;
using FFmpegVideoClip.Lib.AdvancedFragmentProcessor.InternalProcessor;
using FFmpegVideoClip.Mode.Files;
using PropertyChanged;
using UtilityToolsCollect.ObjectsLibrary.ProcessManage;

namespace FFmpegVideoClip.Lib.AdvancedFragmentProcessor
{
    [AddINotifyPropertyChangedInterface, Serializable]
    public class AdvancedTaskFlow : TaskFlowAbstract
    {
        private Dictionary<Fragment, List<AdvancedTaskFlow>> ManageDic;
        public AdvancedTaskFlow(Fragment fragment, int FLowIndex, Dictionary<Fragment, List<AdvancedTaskFlow>> ManageDic)
        {
            this.ManageDic = ManageDic;
            ThisFragment = fragment;
            ThisClip = fragment.clip;
            module = new();
            fragment.clip!.Flows[FLowIndex].DeepCopyTo(module);

            //处理输入

            if (!module.GetInputs(out ParametersSign[] Inputs))
                throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{module.SchemeName}] 缺少输入参数");
            int SelectIndex;
            foreach (ParametersSign CurrentInputParame in Inputs)
            {
                if (!Tools.InputToIndex(CurrentInputParame.Parameter, out SelectIndex))
                    throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{module.SchemeName}]->[{CurrentInputParame.SignName}]:输入参数异常，不是一个可以转换的值");
                //当前流是否队列首个流 或者选择的输入是否是源的输入
                if (FLowIndex < 1 || SelectIndex < 0)
                    CurrentInputParame.Parameter = fragment.InputPath;
                else
                {
                    if (SelectIndex >= FLowIndex)
                        throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{module.SchemeName}]->[{CurrentInputParame.SignName}]" +
                            "流输入选择错误,在流程中目标流晚于当前流，目标流的输出结果尚未产生，无法作为当前流的输入");
                    CurrentInputParame!.Parameter = ManageDic[fragment][SelectIndex].module.GetOutput().Parameter;
                }
            }


            //处理输出
            string Extension = fragment.clip!.Flows[FLowIndex].GetOutput().Parameter.Trim();
            if (!Extension.StartsWith('.'))
                Extension = '.' + Extension;

            string path = fragment.clip.TempCacheDirectory;
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            else
                Tools.ClearEmptyDirectory(path);

            module.GetOutput().Parameter = Path.Combine(path, $"{fragment.Name}_Flow_{FLowIndex}{Extension}");
            //处理时间
            if (module.GetParametersSign(ParametersSign.ETime, out ParametersSign? ETime))
            {
                if (module.IsDurationMode)
                    ETime!.Parameter = Tools.GetTimeSpanToString(fragment.FragmentDuration);
                else ETime!.Parameter = fragment.EndTimeValue;
            }
            if (module.GetParametersSign(ParametersSign.STime, out ParametersSign? STime))
                STime!.Parameter = fragment.StartTimeValue;

            successAndProgress = new SuccessAndProgress(module, fragment);
        }

        public override void Execute()
        {
            string InFileFullPath = module.GetInput().Parameter;
            string OutFileFullPath = module.GetOutput().Parameter;
            successAndProgress.Init();
            successAndProgress.WriteLineNewInfo($"剪辑[{ThisFragment.clip!.Name}]->片段[{ThisFragment.Name}]->流程[{module.SchemeName}]");
            if (string.IsNullOrEmpty(InFileFullPath) || !File.Exists(InFileFullPath))
            {
                successAndProgress.ErrorInfo = $"[{InFileFullPath}]输入文件不存在";
                successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;
                LogManage.WriteLineNewInfo(successAndProgress.ErrorInfo, true);
                return;
            }
            if (string.IsNullOrEmpty(OutFileFullPath) || !Directory.Exists(Path.GetDirectoryName(OutFileFullPath)))
            {
                successAndProgress.ErrorInfo = $"[{OutFileFullPath}]输出路径不存在";
                successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;
                LogManage.WriteLineNewInfo(successAndProgress.ErrorInfo, true);
                return;
            }

            if (File.Exists(OutFileFullPath))
                File.Delete(OutFileFullPath);

            string args = module.GenerateCommandArgument();
            successAndProgress.WriteLineNewInfo($"{module.ProcessorName} {args}");
            CallShell.ShellTypeProcessNameIFSet(module);


            successAndProgress.EnableWriteLog = module.EnableSkipOutputSign;


            if (InternalProcessorSelector.GetSelector(module, out Action<AdvancedParametersSchemeModule, SuccessAndProgress> ProcessExecute))
                ProcessExecute?.Invoke(module, successAndProgress);
            else
                ProcessShell.ProcessExecuteWaitForExit(module.ProcessorName, args, successAndProgress.SuccessValidated, successAndProgress.SuccessValidated);
            if (!successAndProgress.IsSuccess)
                successAndProgress.ErrorInfo = $"处理错误:参数:[{module.ProcessorName}] [{args}]";

            successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;

            if (successAndProgress.EnableWriteLog)
                File.WriteAllText(OutFileFullPath, successAndProgress.Log);


            LogManage.WriteLineNewInfo(successAndProgress.Log);
            successAndProgress.ReleaseScript();

            if (!successAndProgress.IsSuccess)
                throw new AdvancedTaskFlowException($"{successAndProgress.ErrorInfo} Log [{successAndProgress.Log}]");
        }

        [Serializable]
        public class AdvancedTaskFlowException : Exception
        {
            public AdvancedTaskFlowException() { }
            public AdvancedTaskFlowException(string message) : base(message) { }
            public AdvancedTaskFlowException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]protected AdvancedTaskFlowException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }

        protected override void OnDispose()
        {
            ManageDic.Clear();
            ManageDic = null!;
            base.OnDispose();
        }
    }
}
